#include <iostream>
#include <new>
#include <vector>
#include <exception>
#include <cmath>
#include <limits>
#include <stdlib.h>
using namespace std;

///set the machine epsilon.
const double eps = std::numeric_limits<double>::epsilon();

//template <typename T>
//class Matrix;
//template <typename T>
//std::vector<T> operator

template <typename T>
class Matrix
{
 public:
  T **matrix_elements;
  int n_row;
  int n_col;
  void initialize();//initialize the matrix.;
  bool is_square() const;
  Matrix(){
    this->n_col=0;
    this->n_row=0;
      this->matrix_elements=NULL;
  }
  Matrix(int n_row,int n_col);
  Matrix(int n_row,int n_col,T*matrix_elements);//预分配空间
  //  Matrix& operator+=(const Matrix&);//矩阵的+=操作，为乘法做准备
  // Matrix& operator*(const Matrix& m)const;
  Matrix<T>& operator*(Matrix<T> const& secondMatrix) const;//矩阵的乘法
    
  void show() ;//show the matrix
  T point(int i,int j);
  int row() const;
  int col() const;

  //the release.
  ~Matrix()
    {
      if (this->matrix_elements!=NULL)
	{for (int i=0;i<this->row();i++)
	    { delete[] this->matrix_elements[i];
	      delete[]this->matrix_elements;
	    }
	}
    }
  //friend std::istream& operator>>(std::istream,Matrix&);//input the matrix.
  
};
template<typename T>
bool Matrix<T>::is_square() const//
{
  if (this->n_col==this->n_row)
    return true;
    else
      return false;
}

//

template <typename T>
  void Matrix<T>::initialize(){
    //initialize the matrix.
   matrix_elements=new T*[n_row];//分配指针
    for (int i=0;i<n_row;++i){
      matrix_elements[i]=new T[n_col];//动态内存分配
    }
  }

  //
template <typename T>
  Matrix<T>::Matrix(int n_row,int n_col)
    {
      this->n_row=n_row;
      this->n_col=n_col;
      this->matrix_elements=new T*[n_row];
      initialize();
      for (int i=0;i<n_row;i++){
	matrix_elements[i]=new T[n_col];
      }
      for (int i=0;i<n_row;i++){
	for (int j = 0;j<n_col;j++){
	  matrix_elements[i][j]=0;
	}
      }
    }

  //
template <typename T>
Matrix<T>::Matrix(int n_row,int n_col,T*matrix_elements)
// void Matrix<T>::Matrix(int rows,int cols,T value)
    {
      this->n_row=n_row;
      this->n_col=n_col;
      this->matrix_elements=new T* [n_col];
      initialize();
      for (int i = 0;i<n_row;i++){
	matrix_elements[i]=new T[n_col];
      }
      for (int i=0;i<n_row;i++)
      {for (int j = 0;j<n_col;j++){
	  this-> matrix_elements[i][j]=matrix_elements[j+i*(this->n_col)];
	  }
	}
    }
  

//show the matrix.
template <typename T>
 void  Matrix<T>::show() {
    for (int i = 0;i<n_row;i++){
      for(int j=0;j<n_col;j++){
	cout<<matrix_elements[i][j]<<" ";
      }
      cout<<endl;
    }
  }




//////////
template<class T>
Matrix<T>& Matrix<T>::operator*(Matrix<T> const& secondMatrix) const // the reload of "*" in matrix 
{
  if(this->n_col == secondMatrix.row()){
    //cout <<"1"<<endl;
       	Matrix mulm(this->n_row,secondMatrix.col());
       	for(int i=0;i<mulm.row();i++)
       	{
	      	for(int j=0;j< mulm.col();j++)
	       	{
		       	mulm.matrix_elements[i][j] = 0;
		       	for(int k =0;k< this->n_col;k++)
		       	{
			       	mulm.matrix_elements[i][j] += this->matrix_elements[i][k] * secondMatrix.matrix_elements[k][j];
		       	}
	       	}
       	}
       	return mulm;	}
  else{
       	cout << "Error!"<<endl;
       	exit(0);
  }
 }; 

template<class T>
class ColVector : public Matrix<T>  //the subclass colvector of matrix
{
	public:
		ColVector()
		{
			this->n_col = 1;
		}
		ColVector(int n_row)
		{
			this->n_row = n_row;
			this->n_col = 1;
			this->matrix_elements = new T *[n_row];
			for(int i = 0;i < n_row;i++)
			{
				this->matrix_elements[i] = new T [1];
			}
			for (int i=0;i<n_row;i++){
					this->matrix_elements[i][0]=0;
				}
		}
		ColVector(int n_row,T*matrix_elements)
		{
			this->n_row = n_row;
			this->n_col = 1;
			this->matrix_elements = new T *[n_row];
			for(int i = 0;i < n_row;i++)
			{
				this->matrix_elements[i] = new T [1];
			}
			for (int i=0;i<n_row;i++){
				this->matrix_elements[i][0]=matrix_elements[i];
			}
		}
		T operator*(ColVector const& secondColVector) const;
		~ColVector()
		{
			// avoid double free
		}
};

template<class T>
T ColVector<T>::operator*(ColVector<T> const& secondColVector) const //the reload of "*" between colvector
{
	if(this->n_row == secondColVector.row())
		{
			int sum=0;
			for(int k =0;k< this->n_row;k++)
			{
				sum += this->matrix_elements[k][0] * secondColVector.matrix_elements[k][0];
			}
			return sum;
		}
		
	else{
		cout << "Error!"<<endl;
		exit(0); 
	}
}

 
template<class T>
class RowVector : public Matrix<T> //the subclass rowvector of matrix
{
	public:
		RowVector()
		{
			this->n_row=1;
		}
		RowVector(int n_col)
		{
			this->n_row = 1;
			this->n_col = n_col;
			this->matrix_elements = new T *[1];
			for(int i = 0;i < 1;i++)
			{
				this->matrix_elements[i] = new T [n_col];
			}
			for (int i=0;i<1;i++){
				for (int j=0;j<n_col;j++){
					this->matrix_elements[0][j]=0;
				}
			}
		}
		RowVector(int n_col,T*matrix_elements)
		{
			this->n_row = 1;
			this->n_col = n_col;
			this->matrix_elements = new T *[1];
			this->matrix_elements[0] = new T [n_col];
			for (int i=0;i<n_col;i++)
			{
				this->matrix_elements[0][i]=matrix_elements[i];
			}
		}
		T operator*(RowVector const& secondRowVector) const;
		~RowVector()
		{
			// avoid double free. 
		}	
};


template<class T>
T RowVector<T>::operator*(RowVector<T> const& secondRowVector) const //the reload of "*" between rowvector
{
	if(this->n_col == secondRowVector.col())
		{
			int sum=0;
			for(int k =0;k< this->n_col;k++)
			{
				sum += this->matrix_elements[0][k] * secondRowVector.matrix_elements[0][k];
			}
			return sum;
		}
		
	else{
		cout << "Error!"<<endl;
		exit(0); 
	}
	
}

template<class T>
Matrix<T> operator*(ColVector<T>&col,RowVector<T>&row)  // to reload the col * the row
{
	Matrix<T> mulm(col.n_row,row.n_col);
		for(int i=0;i<mulm.row();i++)
		{
			for(int j=0;j< mulm.col();j++)
			{
				mulm.matrix_elements[i][j] = 0;
				mulm.matrix_elements[i][j] += col.matrix_elements[i][0] * row.matrix_elements[0][j];
			}
		}
		return mulm;
}

template<class T>
T operator*(RowVector<T>&row,ColVector<T>&col)  // to reload the row * the col
{
	if (row.n_col == col.n_row)
	{
		T sum = 0;
		for(int i=0;i<row.n_col;i++)
		{
			sum += row.matrix_elements[0][i]*col.matrix_elements[i][0];
		}
		return sum;
	}
	else
	{
		cout << "Error!!!"<< endl;
		exit(0);
	}
}



